package ph.com.gs3.formalistics.service.services;

import java.util.ArrayList;
import java.util.List;

import ph.com.gs3.formalistics.global.utilities.logging.FLLogger;
import ph.com.gs3.formalistics.global.utilities.services.ServiceEventNotifierUtility;
import ph.com.gs3.formalistics.model.communicators.DocumentCommunicatorModule;
import ph.com.gs3.formalistics.model.communicators.HttpCommunicator;
import ph.com.gs3.formalistics.model.dao.DocumentsDAO;
import ph.com.gs3.formalistics.model.dao.FormsDAO;
import ph.com.gs3.formalistics.model.dao.OutgoingDocumentsDAO;
import ph.com.gs3.formalistics.model.dao.OutgoingStarMarksDAO;
import ph.com.gs3.formalistics.model.valueobjects.business.User;
import ph.com.gs3.formalistics.model.valueobjects.business.document.OutgoingDocument;
import ph.com.gs3.formalistics.presenter.MainActivity;
import ph.com.gs3.formalistics.service.managers.DocumentManager;
import ph.com.gs3.formalistics.service.managers.DocumentManager.DocumentActionSubmitFailedException;
import android.app.IntentService;
import android.content.Intent;
import android.os.Bundle;

public class OutgoingDocumentActionSubmitService extends IntentService {

	public static final String TAG = OutgoingDocumentActionSubmitService.class.getSimpleName();
	public static final String NAME = OutgoingDocumentActionSubmitService.class.getName();

	// @formatter:off
	public static final String ACTION_ON_SERVICE_STARTED_SUBMITTING = NAME + "_on_service_started";
	public static final String ACTION_ON_NEW_DOCUMENT_SUBMITTED = NAME + "_on_new_document_submitted";
	public static final String ACTION_ON_EXISTING_DOCUMENT_ACTION_SUBMITTED = NAME + "_on_existing_document_action_submitted";
	public static final String ACTION_ON_SERVICE_DONE = NAME + "_on_service_done";
	// @formatter:on

	// incoming extras
	// public static final String EXTRA_SERVER = "server";
	// public static final String EXTRA_CURRENT_USER_DB_ID = "user_db_id";
	public static final String EXTRA_CURRENT_USER = "current_user";

	// managers
	private DocumentManager documentManager;

	// data access objects
	private OutgoingDocumentsDAO outgoingDocumentsDAO;
	private FormsDAO formsDAO;
	private DocumentsDAO documentsDAO;
	private OutgoingStarMarksDAO outgoingStarMarksDAO;

	// fields
	private User currentUser;

	// private String server;
	// private String currentUserDbId;

	public OutgoingDocumentActionSubmitService() {
		super(TAG);
	}

	@Override
	protected void onHandleIntent(Intent intent) {

		// initialization
		Bundle extras = intent.getExtras();

		initializeFieldsFromExtras(extras);
		initializeDependencies();
		initializeManagers();

		// notify
		Bundle notificationExtras = new Bundle();
		notificationExtras.putSerializable(MainActivity.EXTRA_LOGGED_IN_USER, currentUser);

		ServiceEventNotifierUtility.getDefaultInstance().displayNotificationWithProgress(this,
		        ServiceEventNotifierUtility.NOTIFICATION_ID_PRIMARY,
		        "Sending your outgoing documents", 0, 0, true, notificationExtras);

		String server = currentUser.getAccountServer();
		String currentUserDbId = Integer.toString(currentUser.getId());

		// actual service
		FLLogger.d(TAG, "Service now running");

		List<OutgoingDocument> outgoingDocumentActions = new ArrayList<>();

		int outgoingDocsSentCount = 0;
		int outgoingDocsSentFailCount = 0;

		try {

			outgoingDocumentsDAO.open();
			outgoingDocumentActions = outgoingDocumentsDAO.getAllOutgoingDocument(currentUserDbId);

			// broadcast that the outgoing documents is processing if there are 1 or more
			// documents to process
			if (outgoingDocumentActions.size() > 0) {
				broadcastServiceStarted();
			}

			for (OutgoingDocument outgoingDocumentAction : outgoingDocumentActions) {
				// submit all document actions here;
				FLLogger.d(TAG,
				        "Submitting document action: " + outgoingDocumentAction.getDocumentWebId()
				                + " " + outgoingDocumentAction.getDateIssued() + " "
				                + outgoingDocumentAction.getFieldValues().toString());
				documentManager.submitDocumentAction(outgoingDocumentAction);

				// remove the outgoing document after it's submitted
				outgoingDocumentsDAO.removeOutgoingDocument(server,
				        outgoingDocumentAction.getDocumentWebId());

				if ("0".equals(outgoingDocumentAction.getDocumentWebId())) {
					broadcastNewDocumentSubmitted(outgoingDocumentAction);
				} else {
					broadcastExistingDocumentActionSubmitted(outgoingDocumentAction);
				}

				outgoingDocsSentCount++;
			}
		} catch (DocumentActionSubmitFailedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();

			outgoingDocsSentFailCount++;
		} finally {
			outgoingDocumentsDAO.close();
		}

		FLLogger.d(TAG, "Service done, submitted docs: " + outgoingDocsSentCount + ", failed: "
		        + outgoingDocsSentFailCount);

		ServiceEventNotifierUtility.getDefaultInstance().dismissPrimaryNotification(this);

		finishService();

	}

	private void initializeFieldsFromExtras(Bundle extras) {

		currentUser = (User) extras.getSerializable(EXTRA_CURRENT_USER);

		if (currentUser == null) {
			throw new IllegalArgumentException(
			        "Started DocumentActionSubmitService with an null user");
		}

	}

	private void initializeDependencies() {
		outgoingDocumentsDAO = new OutgoingDocumentsDAO(getApplicationContext());
		formsDAO = new FormsDAO(getApplicationContext());
		documentsDAO = new DocumentsDAO(getApplicationContext());
		outgoingStarMarksDAO = new OutgoingStarMarksDAO(getApplicationContext());
	}

	private void initializeManagers() {

		HttpCommunicator communicator = new HttpCommunicator();
		DocumentCommunicatorModule documentCommModule = new DocumentCommunicatorModule(
		        communicator, currentUser.getAccountServer());

		documentManager = new DocumentManager(formsDAO, documentsDAO, outgoingDocumentsDAO,
		        outgoingStarMarksDAO, documentCommModule);

	}

	private void finishService() {

		broadcastServiceDone();

		// TODO: add broadcaster about finished service here
		stopSelf();
	}

	// =========================================================================================
	// {{ Broadcast Methods

	private void broadcastServiceStarted() {
		Intent broadcastIntent = new Intent();
		broadcastIntent.setAction(ACTION_ON_SERVICE_STARTED_SUBMITTING);
		broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
		sendBroadcast(broadcastIntent);
	}

	private void broadcastExistingDocumentActionSubmitted(OutgoingDocument outgoingDocumentAction) {

		Intent broadcastIntent = new Intent();
		broadcastIntent.setAction(ACTION_ON_EXISTING_DOCUMENT_ACTION_SUBMITTED);
		broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
		sendBroadcast(broadcastIntent);

	}

	private void broadcastNewDocumentSubmitted(OutgoingDocument outgoingDocumentAction) {

		Intent broadcastIntent = new Intent();
		broadcastIntent.setAction(ACTION_ON_NEW_DOCUMENT_SUBMITTED);
		broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
		sendBroadcast(broadcastIntent);

	}

	private void broadcastServiceDone() {
		Intent broadcastIntent = new Intent();
		broadcastIntent.setAction(ACTION_ON_SERVICE_DONE);
		broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
		sendBroadcast(broadcastIntent);
	}

	// }}

}
